package com.simple.mipc.cast;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class StringAutoCast<T> implements ParamCast<T> {

    private Map<Class<?>, ParamCast<?>> map = new HashMap<>();

    public StringAutoCast() {
        ByteStringCast byteStringCast = new ByteStringCast();
        map.put(byte.class, byteStringCast);
        map.put(Byte.class, byteStringCast);
        ShortStringCast shortStringCast = new ShortStringCast();
        map.put(short.class, shortStringCast);
        map.put(Short.class, shortStringCast);
        CharStringCast charStringCast = new CharStringCast();
        map.put(char.class, charStringCast);
        map.put(Character.class, charStringCast);
        IntStringCast intStringCast = new IntStringCast();
        map.put(int.class, intStringCast);
        map.put(Integer.class, intStringCast);
        LongStringCast longStringCast = new LongStringCast();
        map.put(long.class, longStringCast);
        map.put(Long.class, longStringCast);
        FloatStringCast floatStringCast = new FloatStringCast();
        map.put(float.class, floatStringCast);
        map.put(Float.class, floatStringCast);
        DoubleStringCast doubleStringCast = new DoubleStringCast();
        map.put(double.class, doubleStringCast);
        map.put(Double.class, doubleStringCast);
        BooleanStringCast booleanStringCast = new BooleanStringCast();
        map.put(boolean.class, booleanStringCast);
        map.put(Boolean.class, booleanStringCast);
        StringStringCast stringStringCast = new StringStringCast();
        map.put(String.class, stringStringCast);

    }

    @Override
    public T castTo(Object obj, Class<T> clazz) {
        if (!check(obj, clazz)) {
            throw new IllegalArgumentException("无法转换的类型");
        }
        ParamCast<T> paramCast = (ParamCast<T>) map.get(clazz);
        String source = String.valueOf(obj);
        return paramCast.castTo(source, clazz);
    }

    @Override
    public boolean check(Object obj, Class<T> clazz) {
        ParamCast<T> paramCast = (ParamCast<T>) map.get(clazz);
        return Objects.nonNull(paramCast) && paramCast.check(obj, clazz);
    }

    static abstract class AbstractStringCast<T> implements ParamCast<T> {

        @Override
        public boolean check(Object obj, Class<T> clazz) {
            return obj instanceof String;
        }
    }

    static class ByteStringCast extends AbstractStringCast<Byte> {

        @Override
        public Byte castTo(Object obj, Class<Byte> clazz) {
            String source = (String) obj;
            return Byte.valueOf(source);
        }
    }

    static class ShortStringCast extends AbstractStringCast<Short> {

        @Override
        public Short castTo(Object obj, Class<Short> clazz) {
            String source = (String) obj;
            return Short.valueOf(source);
        }
    }

    static class CharStringCast extends AbstractStringCast<Character> {

        @Override
        public Character castTo(Object obj, Class<Character> clazz) {
            String source = (String) obj;
            return source.charAt(0);
        }
    }

    static class IntStringCast extends AbstractStringCast<Integer> {

        @Override
        public Integer castTo(Object obj, Class<Integer> clazz) {
            String source = (String) obj;
            return Integer.valueOf(source);
        }
    }

    static class LongStringCast extends AbstractStringCast<Long> {

        @Override
        public Long castTo(Object obj, Class<Long> clazz) {
            String source = (String) obj;
            return Long.valueOf(source);
        }
    }

    static class FloatStringCast extends AbstractStringCast<Float> {

        @Override
        public Float castTo(Object obj, Class<Float> clazz) {
            String source = (String) obj;
            return Float.valueOf(source);
        }
    }

    static class DoubleStringCast extends AbstractStringCast<Double> {

        @Override
        public Double castTo(Object obj, Class<Double> clazz) {
            String source = (String) obj;
            return Double.valueOf(source);
        }
    }

    static class BooleanStringCast extends AbstractStringCast<Boolean> {

        @Override
        public Boolean castTo(Object obj, Class<Boolean> clazz) {
            String source = (String) obj;
            return Boolean.valueOf(source);
        }
    }

    static class StringStringCast extends AbstractStringCast<String> {

        @Override
        public String castTo(Object obj, Class<String> clazz) {
            return (String) obj;
        }
    }
}
